package clickhouse.util;

import clickhouse.util.StrUtil2;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
public class StrUtil extends StrUtil2
{
	public StrUtil()
	{
	}
	/**
	 * 将字符数组内的元素转换大小写
	 * @param arr
	 * @param isUpperCase  true转大写  false  转小写
	 * @return
	 */
	static public String[] toCaseArray(String[] arr, boolean isUpperCase)
	{
		if (arr != null)
		{
			int i = 0;
			for (String s : arr)
			{
				if (isUpperCase)
					arr[i] = s.toUpperCase();
				else
					arr[i] = s.toLowerCase();
				i++;
			}
		}
		return arr;
	}
	/**
	 * 判断字符串数组中是否所有元素均是eqlStr  add by 胡俊岩
	 * @param str
	 * @param eqlStr
	 * @return
	 */
	static public boolean isSameElements(String[] str, String eqlStr)
	{
		boolean isSameElements = true;
		if (str != null && str.length > 1)
		{
			Set<String> strSet = new HashSet<String>();
			for (String s : str)
			{
				strSet.add(s);
			}
			isSameElements = strSet.size() == 1 && strSet.contains(eqlStr) ? true : false;
		}
		return isSameElements;
	}
	/**
	 * 取字符串长度，汉字算两个字符 add by 胡俊岩
	 * @param s
	 * @return
	 */
	static public int getStringLengthForAscII(String s)
	{
		if (s != null)
		{
			int l = 0;
			int sl = s.length();
			for (int i = 0; i < sl; i++)
			{
				char c = s.charAt(i);
				l += (c > 0x80) ? 2 : 1;
			}
			return l;
		}
		return 0;
	}
	/**
	 * 取子串，汉字算两个字符，不能将汉字分开，回车换行也不能分开  add by 胡俊岩
	 * @param s
	 * @param endIndex
	 * @return
	 */
	static public String subStringForAscII(String s, int endIndex)
	{
		if (s == null)
			return null;
		// if (!ediBuildObject.isAscII())
		// return s.substring(0,endIndex);
		int tl = 0;
		String sub = "";
		int sl = s.length();
		for (int i = 0; i < sl; i++)
		{
			char c = s.charAt(i);
			// 回车换行或汉字长度算2
			int l = ((c == '\r' && i < sl - 1 && s.charAt(i + 1) == '\n') || c > 0x80) ? 2 : 1;
			if ((tl + l) > endIndex)
				break;
			tl += l;
			sub += c;
		}
		return sub;
	}
	/**
	 * 取字符串交集
	 * @param srcStr 源字符串集
	 * @param subStr 源字符串集
	 * @param del 分隔符
	 * @return
	 */
	public static String getInterSet(String srcStr, String subStr, char del)
	{
		if (srcStr == null || subStr == null)
			return null;
		String[] srces = splitString(srcStr, del);
		StringBuilder sb = new StringBuilder();
		for (String src : srces)
		{
			if (src == null || src.length() == 0)
				continue;
			if (!isStrIn(subStr, src))
				continue;
			if (sb.length() > 0)
				sb.append(del);
			sb.append(src);
		}
		if (sb.length() > 0)
			return sb.toString();
		return null;
	}
	/**
	 * 返回两个字符串的差集【srcStr-subStr】，默认使用逗号分隔.
	 * 测试1:
	 * 源：System.err.println(getDiffset("1,2,11,1,,", "1"));
	 * 终端：2,11
	 * @param srcStr 源字符串
	 * @param subStr 被减字符串
	 * @return 差集
	 */
	public static String getDiffset(String srcStr, String subStr)
	{
		if (srcStr == null || subStr == null)
			return srcStr;
		StringBuilder sb = new StringBuilder();
		for (String src : srcStr.split(","))
		{
			if (src.length() == 0 || isStrIn(subStr, src))
				continue;
			if (sb.length() > 0)
				sb.append(',');
			sb.append(src);
		}
		return sb.toString();
	}
	/**
	 * 判断字段串 s是否在字段串strList中
	 * @param strList 可理解为源字符串
	 * @param s 想要在源字符串中查找的字符串
	 * @return 如果存在返回true,如果不存在返回false
	 */
	static public boolean isStrIn(String strList, String s)
	{
		return isStrIn(strList, s, ',');
	}
	/**
	 * 判断字段串 s是否在字段串strList中
	 * @param strList 可理解为源字符串
	 * @param s 想要在源字符串中查找的字符串
	 * @param delimiter 分隔符
	 * @return 如果存在返回true,如果不存在返回false
	 */
	public static boolean isStrIn(String strList, String s, char delimiter)
	{
		return indexOf(strList, delimiter, s, false, false) >= 0;
	}
	/**
	 * 将集合collection中的所有元素转换成以逗号分隔的字符串返回。
	 * @param collection 想要转换的源数据集合
	 * @return 转化完成的以逗号分隔的字符串
	 */
	static public String toString(Collection<?> collection)
	{
		if (collection != null && collection.size() > 0)
		{
			return toString(collection.toArray());
		}
		return null;
	}
	/**
	 * 将一维数组vs转换成逗号分隔的字符串返回。
	 * @param vs 数组
	 * @return
	 */
	static public String toString(Object[] vs)
	{
		return toString(vs, ',');
	}
	/**
	 * 将一维数组vs转换成指定分隔符分隔的字符串返回。
	 * 注意：vs中的null会被过滤。
	 * @param vs 一维数组
	 * @return 如果vs为null，或长度为零，或元素全部为空则返回null；否则返回逗号分隔的字符串。
	 */
	public static String toString(Object[] vs, char deli)
	{
		if (vs != null && vs.length > 0)
		{
			StringBuilder sb = new StringBuilder();
			for (Object v : vs)
			{
				if (v == null)
					continue;
				if (sb.length() > 0)
					sb.append(deli);
				sb.append(v);
			}
			if (sb.length() > 0)
				return sb.toString();
		}
		return null;
	}
	/**
	 * 将字符串解析成key=value，用于配置字段拷贝关系。
	 * 字符串格式："field1=field2,field3,..."格式；
	 * 注意：格式允许的两种情况：
	 * 1、如果同名则配置一个字段即可如field3，则存入Map中：key=field3,value=field3
	 * 2、 如果不同名如field1=field2，则存入Map中：key=field1,value=field2
	 */
	public static Map<String,String> getFieldMap(String str)
	{
		return getKeyValueMap(str, ',', '=', true);
	}
	/**
	 * TAC:
	 * str = ""
	 * map = snsoft.abas.util.pub.StrUtil.getKeyValueMap(str,',','=',true)
	 * getProgress.addMessage(map.toString())
	 * snsoft.abas.util.pub.StrUtil.getKeyValueMap
	 * @param str 源字符串
	 * @param first 第一分隔符
	 * @param second 第二分隔符
	 * @param keyAsValue 如果没有配置值，则把key作为值
	 * @return
	 */
	public static Map<String,String> getKeyValueMap(String str, char first, char second, boolean keyAsValue)
	{
		Map<String,String> map = new LinkedHashMap<String,String>();
		if (str != null)
		{
			String[] fields = splitString(str, first);
			for (String field : fields)
			{
				if (field == null || (field = field.trim()).length() == 0)
					continue;
				int idx = field.indexOf(second);
				if (idx >= 0)
				{
					String key = field.substring(0, idx);
					String value = field.substring(idx + 1);
					map.put(key, value);
				} else
				{
					map.put(field, keyAsValue ? field : null);
				}
			}
		}
		return map;
	}
	/**
	 * 将Map转换成字符串
	 * @param map 数据源
	 * @param first 第一分隔符
	 * @param second 第二分隔符
	 * @param filterNull 是否过滤空值
	 * @return
	 */
	public static <K,V> String toString(Map<K,V> map, char first, char second, boolean filterNull)
	{
		if (map == null)
			return null;
		StringBuilder sb = new StringBuilder();
		for (Entry<K,V> e : map.entrySet())
		{
			if (filterNull && e.getValue() == null)
				continue;
			if (sb.length() > 0)
				sb.append(first);
			sb.append(e.getKey());
			sb.append(second);
			Object value = e.getValue();
			if (value != null)
			{
				String str = null;
				if (value instanceof Date)
					str = String.format("%1$tF", value);
				else
					str = StrUtil.obj2str(value);
				sb.append(str);
			}
		}
		return sb.length() == 0 ? null : sb.toString();
	}
	/**
	 * 返回调用此方法的程序位置打印在Eclipse的终端上用于定位程序代码。
	 * @return 调用此方法的程序位置
	 */
	public static String getLocation()
	{
		return new RuntimeException().getStackTrace()[1].toString();
	}
	/**
	 * 将数组转换成逗号分隔的字符串形式
	 * @param o 数组
	 * @return 逗号分隔的字符串
	 */
	public static <E> String toCSVString(E[] o)
	{
		return toString(o);
	}
	/**
	 * 将可迭代的容器的内容,转换成逗号分隔的字符串形式
	 * @param o 可跌的的容器
	 * @return 逗号分隔的字符串
	 */
	public static String toCSVString(Iterable o)
	{
		if (o == null)
		{
			return null;
		}
		StringBuffer sb = new StringBuffer();
		for (Object temp : o)
		{
			if (sb.length() > 0)
			{
				sb.append(",");
			}
			sb.append(StrUtil.obj2str(temp));
		}
		return sb.toString();
	}
	/**
	 * 将二维数组中的指定列转换为逗号分隔的字符串形式
	 * @param o 二维数组
	 * @param index2 列下标
	 * @return 逗号分隔的字符串
	 */
	public static <E> String toCSVString(E[][] o, int index2)
	{
		if (o == null || o.length == 0)
		{
			return null;
		}
		StringBuffer sb = new StringBuffer();
		for (E[] temp : o)
		{
			if (sb.length() > 0)
			{
				sb.append(",");
			}
			sb.append(obj2str(temp[index2]));
		}
		return sb.toString();
	}
	/**
	 * 将二维数组中的指定的两列,用连接符连接起来,将连接后的字符串在连接为逗号分隔的字符串形式
	 * @param o 二维数组
	 * @param index2_1 第一列的下标
	 * @param link 两列字段直接的连接符
	 * @param index2_2 第二列的下标
	 * @return 逗号分隔的字符串
	 */
	public static <E> String toCSVString(E[][] o, int index2_1, String link, int index2_2)
	{
		if (o == null || o.length == 0)
		{
			return null;
		}
		StringBuffer sb = new StringBuffer();
		for (E[] temp : o)
		{
			if (sb.length() > 0)
			{
				sb.append(",");
			}
			sb.append(strcat(obj2str(temp[index2_1]), link, obj2str(temp[index2_2])));
		}
		return sb.toString();
	}
	/**
	 * 判断字符串是否为空
	 * @param str
	 * @return 空返回true
	 */
	static public boolean isStrTrimNull(String str)
	{
		return (str == null || str.trim().length() == 0 || str.equalsIgnoreCase("null"));
	}
	/**
	 * 从字符串中删除某个字串 并且返回 例如：removeSubStr("a,b,c",',',"c") 返回"a,b"
	 * @param str 源字符串
	 * @param delimiter 分隔符
	 * @param subStr 要删除的字符串
	 * @return
	 */
	public static String removeSubStr(String str, char delimiter, String subStr)
	{
		String[] strs = splitString(str, delimiter);
		for (int i = 0; i < strs.length; i++)
		{
			if (strs[i].equals(subStr))
				strs[i] = null;
		}
		String newStr = null;
		for (int i = 0; i < strs.length; i++)
		{
			newStr = strcat(newStr, delimiter, strs[i]);
		}
		return newStr;
	}

	/**
	 * add by wangwei 2019-4-22
	 * 从字符串中删除某个字串 并且返回 例如：removeSubStr("aa,ba,cc",',',"c") 返回"a,b"
	 * @param str 源字符串
	 * @param delimiter 分隔符
	 * @param subStr 要删除的字符串开头
	 * @return
	 */
	public static String removeLikeSubStr(String str, char delimiter, String subStr)
	{
		String[] strs = splitString(str, delimiter);
		for (int i = 0; i < strs.length; i++)
		{
			if (strs[i].startsWith(subStr))
				strs[i] = null;
		}
		String newStr = null;
		for (int i = 0; i < strs.length; i++)
		{
			newStr = strcat(newStr, delimiter, strs[i]);
		}
		return newStr;
	}

	static public final String obj2str(Object text, String defaultvalue)
	{
		return text != null ? text.toString() : defaultvalue;
	}
	/**
	 * 传入字符串，及递增后链表长度，返回递增的字符串（包含源字符串）。
	 * @param srcStr 源字符串 形如： "0000"等
	 * @param tgtLength 递增后的数据链表长度
	 * @return 递增到长度为2后 返回{"0000","0001"}
	 */
	public static List<String> getAutoIncreaseStrList(String srcStr, int tgtLength)
	{
		List<String> list = new ArrayList<String>();
		if (isStrTrimNull(srcStr) || tgtLength <= 0 || !srcStr.matches("^[0-9]+$"))
			return list;
		int len = srcStr.length();
		BigInteger numberValue = new BigInteger(srcStr);
		for (int cnt = 0; cnt < tgtLength; cnt++)
		{
			list.add("" + numberValue);
			numberValue = numberValue.add(BigInteger.ONE);
		}
		for (int i = 0; i < list.size(); i++)
		{
			String tempStr = list.get(i);
			int subDigits = len - tempStr.length();
			for (int j = 0; j < subDigits && subDigits > 0; j++)
			{
				tempStr = "0" + tempStr;
			}
			list.set(i, tempStr);
		}
		return list;
	}
	/**
	 * 判断字符串是否为空
	 * @param str
	 * @return 空返回true
	 */
	static public boolean isNull(String str)
	{
		return (str == null || str.length() == 0);
	}
	/**
	 * 判断字符串是否不为空
	 * @param str
	 * @return 空返回true
	 */
	static public boolean isNotNull(String str)
	{
		return !isNull(str);
	}
	/**
	 * 判断字符串是否不为为空
	 * @param str
	 * @return 空返回true
	 */
	static public boolean isNotStrTrimNull(String str)
	{
		return !isStrTrimNull(str);
	}

	/**
	 * 对源字符串进行增删操作，会自动去重
	 * @param src 源字符串
	 * @param del 源字符串分隔符
	 * @param cur 当前字符串
	 * @param options 增删选项
	 * 		1：增加，默认删除；
	 * 		2：排序，默认不排序；
	 * @return 任何无效操作将返回null；
	 */
	public static String operate(String src, char del, String cur, int options)
	{
		if (src == null)
			return (options & 1) != 0 ? cur : null;
		if (cur == null)
			return src;
		String[] srcs = splitString(src, del);
		Set<String> set = (options & 2) != 0 ? new TreeSet() : new LinkedHashSet();
		for (String s : srcs)
			set.add(s);
		if ((options & 1) != 0)
			set.add(cur);
		else
			set.remove(cur);
		String value = toString(set.toArray(), del);
		return value;
	}
	public static String getInFilter(String values)
	{
		return filterFormat(",", "'%0'", null, values, false);
	}
	public static String strcatStr(String s1, String link, String s2)
	{
		return StrUtil.strcat(s1, link, s2);
	}
	/**
	 *
	 * @param str
	 * @return
	 */
	static public String trimString(String str)
	{
		if (str != null && str.trim().length() > 0 && str.trim().startsWith("\"") && str.trim().endsWith("\""))
		{
			int len = str.trim().length();
			String newStr = str.trim().substring(1, len - 1);
			return newStr.trim();
		}
		return str == null ? null : str.trim();
	}
	/**
	 * 例如  getNumByFixLength(5,3)
	 *    返回 005
	 * @param num 整数
	 * @param length 长度
	 * add by LP
	 * @return
	 */
	static public String getNumByFixLength(int num, int length)
	{
		String format = "%0" + length + "d";
		String numStr = String.format(format, num);
		return numStr;
	}

	/**
	 * ASCII表中可见字符从!开始，偏移位值为33(Decimal)
	 */
	static final char DBC_CHAR_START = 33; // 半角!

	/**
	 * ASCII表中可见字符到~结束，偏移位值为126(Decimal)
	 */
	static final char DBC_CHAR_END = 126; // 半角~

	/**
	 * 全角对应于ASCII表的可见字符从！开始，偏移值为65281
	 */
	static final char SBC_CHAR_START = 65281; // 全角！

	/**
	 * 全角对应于ASCII表的可见字符到～结束，偏移值为65374
	 */
	static final char SBC_CHAR_END = 65374; // 全角～

	/**
	 * ASCII表中除空格外的可见字符与对应的全角字符的相对偏移
	 */
	static final int CONVERT_STEP = 65248; // 全角半角转换间隔

	/**
	 * 全角空格的值，它没有遵从与ASCII的相对偏移，必须单独处理
	 */
	static final char SBC_SPACE = 12288; // 全角空格 12288

	/**
	 * 半角空格的值，在ASCII中为32(Decimal)
	 */
	static final char DBC_SPACE = ' '; // 半角空格



	/**
	 * 全角字符->半角字符转换
	 * 只处理全角的空格，全角！到全角～之间的字符，忽略其他
	 * @param src
	 * @return
	 *  hongpenghui 2018年8月16日上午11:09:22
	 *  任务号:
	 */
	public static String doubleByte2SingleByte(String src) {
		if (src == null) {
			return src;
		}
		StringBuilder buf = new StringBuilder(src.length());
		char[] ca = src.toCharArray();
		for (int i = 0; i < src.length(); i++) {
			if (ca[i] >= SBC_CHAR_START && ca[i] <= SBC_CHAR_END) { // 如果位于全角！到全角～区间内
				buf.append((char) (ca[i] - CONVERT_STEP));
			} else if (ca[i] == SBC_SPACE) { // 如果是全角空格
				buf.append(DBC_SPACE);
			} else { // 不处理全角空格，全角！到全角～区间外的字符
				buf.append(ca[i]);
			}
		}
		return buf.toString();
	}

	/**
	 * 半角字符->全角字符转换
	 * 只处理空格，!到˜之间的字符，忽略其他
	 * @param src
	 * @return
	 *  hongpenghui 2018年8月30日上午8:49:25
	 *  任务号:
	 */
	public static String singleByte2DoubleByte(String src) {
		if (src == null) {
			return src;
		}
		StringBuilder buf = new StringBuilder(src.length());
		char[] ca = src.toCharArray();
		for (int i = 0; i < ca.length; i++) {
			if (ca[i] == DBC_SPACE) { // 如果是半角空格，直接用全角空格替代
				buf.append(SBC_SPACE);
			} else if ((ca[i] >= DBC_CHAR_START) && (ca[i] <= DBC_CHAR_END)) { // 字符是!到~之间的可见字符
				buf.append((char) (ca[i] + CONVERT_STEP));
			} else { // 不对空格以及ascii表中其他可见字符之外的字符做任何处理
				buf.append(ca[i]);
			}
		}
		return buf.toString();
	}
	/**
	 * added by linjinhai NEWERP-38812 2020-06-08
	 * 处理账号存在特殊字符移除
	 * @param ccodeName
	 * @return
	 */
	public static String replaceWord(String ccodeName) {
		if (StrUtil.isNotStrTrimNull(ccodeName)) {
			String[] fbsArr = { "\\","$","(",")","*","+",".","[", "]","?","^","{","}","|","'","%","-","_","（","）"," "};
			for (String key : fbsArr) {
				if (ccodeName.contains(key)) {
					ccodeName = ccodeName.replace(key,"");
				}
			}
		}
		return ccodeName;
	}

	/**
	 * 合并字符串
	 * @param delimiter
	 * @param list
	 * @param col
	 * @return
	 * @author leizuman
	 * @date   2021年6月29日
	 */
	public static String joinListMap(String delimiter, List<Map<String,Object>> list, String col){
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < list.size(); i++){
			Map<String,Object> sspg = list.get(i);
			if (i > 0){
				sb.append(delimiter);
			}
			sb.append(sspg.get(col));
		}
		return sb.toString();
	}

	/**
	 * 字符串
	 * @param delimiter
	 * @param arr
	 * @return
	 * @author leizuman
	 * @date   2021年7月14日
	 */
	public static String join(String delimiter, Object[] arr){
		StringBuilder sb = new StringBuilder();
		for(int i = 0;i < arr.length; i++){
			if (i > 0){
				sb.append(delimiter);
			}
			sb.append(arr[i]);
		}
		return sb.toString();
	}

	/**
	 * add by wangwei NEWERP-48799 2021-12-28
	 * 判断字符串str的字符集是否是encode
	 * @param str
	 * @param encode
	 * @return
	 */
	public static boolean isEncode(String str,String encode){
		if(isNull(str))
			return true;
		try{
			if(str.equals(new String(str.getBytes(encode),encode))){
				return true;
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		return false;
	}

}